package com.example.foodtruckdemo.service.impl;

import ch.hsr.geohash.GeoHash;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.foodtruckdemo.common.ApiResult;
import com.example.foodtruckdemo.controller.vo.GeoHashVo;
import com.example.foodtruckdemo.controller.vo.MobileFoodFacilityPermitPageByPositionReq;
import com.example.foodtruckdemo.controller.vo.MobileFoodFacilityPermitPageReq;
import com.example.foodtruckdemo.controller.vo.MobileFoodFacilityPermitPageVo;
import com.example.foodtruckdemo.domain.MobileFoodFacilityPermit;
import com.example.foodtruckdemo.service.MobileFoodFacilityPermitService;
import com.example.foodtruckdemo.mapper.MobileFoodFacilityPermitMapper;
import com.example.foodtruckdemo.util.GpsDistanceUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.support.TransactionTemplate;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
* @author jin
* @description 针对表【Mobile_Food_Facility_Permit_csv】的数据库操作Service实现
* @createDate 2024-09-03 12:25:30
*/
@Service
public class MobileFoodFacilityPermitServiceImpl extends ServiceImpl<MobileFoodFacilityPermitMapper, MobileFoodFacilityPermit>
    implements MobileFoodFacilityPermitService{

    @Resource
    private TransactionTemplate transactionTemplate;
    @Override
    public ApiResult<List<MobileFoodFacilityPermitPageVo>> page(MobileFoodFacilityPermitPageReq req) {
        Page<MobileFoodFacilityPermitPageVo> pageData = baseMapper.page(req.toPage(), req);

        return ApiResult.success(pageData);
    }

    @Override
    public void updateGeoHash() {
        Page page = new Page(1, 500);
        while(true) {
            Page<GeoHashVo> pageData = baseMapper.getBlankGeohash(page);
            if (pageData == null || pageData.getRecords() == null || pageData.getRecords().size() == 0){
                return;
            }
            updateGeoHash(pageData.getRecords());
            if(!pageData.hasNext()){
                return;
            }
        }
    }

    @Override
    public ApiResult<List<MobileFoodFacilityPermitPageVo>> getByPosition(MobileFoodFacilityPermitPageByPositionReq req) {
        GeoHash poisition = GeoHash.withCharacterPrecision(req.getLatitude(), req.getLongitude(), 12);
        GeoHash[] adjacent = poisition.getAdjacent();
        List<MobileFoodFacilityPermitPageVo> results = Collections.emptyList();
        for(int length = 12; length > 0; length--){
            int finalLength = length;
            List<String> geoHashCodePrefixs = Arrays.stream(adjacent).map(e -> e.toBase32().substring(0, finalLength)).distinct().collect(Collectors.toList());
            int count = baseMapper.countByPosition(req,geoHashCodePrefixs);
            if(count > req.getCount()){
                results = baseMapper.getByPosition(req,geoHashCodePrefixs);
                break;
            }
        }
        /**
         * 计算距离
         */
        calcDistance(req.getLatitude(), req.getLongitude(),results);
        //按距离排序
        results.sort(Comparator.comparingDouble(MobileFoodFacilityPermitPageVo::getDistance));
        return ApiResult.success(req.getCount() > results.size() ? results : results.subList(0,req.getCount()));
    }

    /**
     * 计算餐车与位置距离
     * @param latitude
     * @param longitude
     * @param results
     */
    private void calcDistance(Double latitude, Double longitude, List<MobileFoodFacilityPermitPageVo> results) {
        for (MobileFoodFacilityPermitPageVo mobileFoodFacilityPermitPageVo : results) {
            mobileFoodFacilityPermitPageVo.setDistance(GpsDistanceUtils.getDistance(longitude,latitude,mobileFoodFacilityPermitPageVo.getLongitude(),mobileFoodFacilityPermitPageVo.getLatitude(),6));
        }
    }


    private void updateGeoHash(List<GeoHashVo> records) {
        for (GeoHashVo record : records) {
            String geohash = GeoHash.geoHashStringWithCharacterPrecision(record.getLatitude(), record.getLongitude(), 12);
            record.setGeohash(geohash);
        }
        transactionTemplate.executeWithoutResult(transactionStatus -> {
            baseMapper.updateGeoHash(records);
        });
    }
}




